using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using HslCommunicationEx.OpcUa.Client;
using Newtonsoft.Json;
using Opc.Ua;
using Opc.Ua.Security.Certificates;
using Catastrophe.Common;

namespace HslCommunicationEx.OpcUa
{
	public class OpcUaUtil
	{
		public static ApplicationConfiguration CreateClientConfiguration()
		{
			ApplicationConfiguration applicationConfiguration = new ApplicationConfiguration();
			applicationConfiguration.ApplicationName = "Catastrophe Opc Ua Client";
			applicationConfiguration.ApplicationType = ApplicationType.Client;
			applicationConfiguration.ApplicationUri = "urn:MyClient";
			applicationConfiguration.ProductUri = "SYTL";
			applicationConfiguration.SecurityConfiguration = new SecurityConfiguration();
			applicationConfiguration.SecurityConfiguration.ApplicationCertificate = new CertificateIdentifier();
			applicationConfiguration.SecurityConfiguration.ApplicationCertificate.StoreType = "X509Store";
			applicationConfiguration.SecurityConfiguration.ApplicationCertificate.StorePath = "CurrentUser\\My";
			applicationConfiguration.SecurityConfiguration.ApplicationCertificate.SubjectName = applicationConfiguration.ApplicationName;
			applicationConfiguration.SecurityConfiguration.TrustedIssuerCertificates.StoreType = "X509Store";
			applicationConfiguration.SecurityConfiguration.TrustedIssuerCertificates.StorePath = "CurrentUser\\Root";
			applicationConfiguration.SecurityConfiguration.TrustedPeerCertificates.StoreType = "X509Store";
			applicationConfiguration.SecurityConfiguration.TrustedPeerCertificates.StorePath = "CurrentUser\\Root";
          
            X509Certificate2 result = applicationConfiguration.SecurityConfiguration.ApplicationCertificate.Find(needPrivateKey: true).Result;
			if (result == null)
			{
				List<string> localIpAddressAndDns = OpcUaUtil.GetLocalIpAddressAndDns();
				ushort rSAKeySize = 2048;
				ushort lifeTime = 1200;
				ushort num = 1;
				string subjectName = "CN=" + applicationConfiguration.ApplicationName + ", C=China, S=SY, O=OPC Foundation";
				result = CertificateBuilder.Create(subjectName).AddExtension(new X509SubjectAltNameExtension(applicationConfiguration.ApplicationUri, localIpAddressAndDns)).SetHashAlgorithm(HashAlgorithmName.SHA256)
					.SetLifeTime(lifeTime)
					.SetRSAKeySize(rSAKeySize)
					.CreateForRSA()
					.AddToStore(applicationConfiguration.SecurityConfiguration.ApplicationCertificate.StoreType, applicationConfiguration.SecurityConfiguration.ApplicationCertificate.StorePath);
			}
			applicationConfiguration.TransportQuotas = new TransportQuotas();
			applicationConfiguration.TransportQuotas.OperationTimeout = 360000;
			applicationConfiguration.TransportQuotas.MaxStringLength = 67108864;
			applicationConfiguration.TransportQuotas.MaxByteStringLength = 16777216;
            applicationConfiguration.TransportQuotas.MaxMessageSize = 10485760;
            applicationConfiguration.ClientConfiguration = new ClientConfiguration();
			applicationConfiguration.ClientConfiguration.DefaultSessionTimeout = 360000;
			applicationConfiguration.Validate(ApplicationType.Client);
			return applicationConfiguration;
		}

		public static List<string> GetLocalIpAddressAndDns()
		{
			List<string> list = new List<string>();
			IPHostEntry hostEntry = Dns.GetHostEntry(Dns.GetHostName());
			IPAddress[] addressList = hostEntry.AddressList;
			foreach (IPAddress iPAddress in addressList)
			{
				if (iPAddress.AddressFamily == AddressFamily.InterNetwork)
				{
					list.Add(iPAddress.ToString());
				}
			}
			if (list.Count == 0)
			{
				throw new Exception("Local IP Address Not Found!");
			}
			list.Add(Dns.GetHostName());
			return list;
		}

		public static EndpointDescription CreateEndpointDescription(string url, string secPolicy, MessageSecurityMode msgSecMode, ServerIdentityEntity identity = null)
		{
			EndpointDescription endpointDescription = new EndpointDescription();
			endpointDescription.EndpointUrl = url;
			endpointDescription.SecurityPolicyUri = secPolicy;
			endpointDescription.SecurityMode = msgSecMode;
			endpointDescription.TransportProfileUri = "http://opcfoundation.org/UA-Profile/Transport/uatcp-uasc-uabinary";
			UserTokenPolicy item = new UserTokenPolicy
			{
				TokenType = UserTokenType.Anonymous
			};
			endpointDescription.UserIdentityTokens.Add(item);
			if (identity != null)
			{
				endpointDescription.ServerCertificate = identity.Certificate;
				endpointDescription.UserIdentityTokens = identity.TokenCollection;
			}
			return endpointDescription;
		}

		public static string GetEndpointIdentityJson(EndpointDescription endpoint)
		{
			return JsonConvert.SerializeObject(OpcUaUtil.GetEndpointIdentityEntity(endpoint));
		}

		public static ServerIdentityEntity GetEndpointIdentityEntity(EndpointDescription endpoint)
		{
			if (endpoint == null)
			{
				throw new ArgumentNullException("endpoint");
			}
			return new ServerIdentityEntity
			{
				Certificate = endpoint.ServerCertificate,
				TokenCollection = endpoint.UserIdentityTokens
			};
		}

		public static ServerIdentityEntity GetEndpointIdentityEntity(string jsonValue, string deviceNo)
		{
			if (string.IsNullOrEmpty(jsonValue))
			{
				throw new ArgumentNullException("jsonValue");
			}
			if (deviceNo == null)
			{
				throw new ArgumentNullException("deviceNo");
			}
			Tuple<bool, Dictionary<string, ServerIdentityEntity>> tuple = DataConverter.TryJsonDeserialize<Dictionary<string, ServerIdentityEntity>>(jsonValue);
			return (tuple.Item2?.ContainsKey(deviceNo) ?? false) ? tuple.Item2[deviceNo] : null;
		}
	}
}
